package com.fqr;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;


public class DateSymbolParser {
	static DateFormat DF_SHORT = new SimpleDateFormat("MM/dd/yyyy");

	static DateFormat DF_LONG = new SimpleDateFormat("MM/dd/yyyy:HH:mm:ss");

	public static String parse(String d) {
		return parse(d, DF_LONG);
	}

	static {
		DF_SHORT.setLenient(false);
	}
	
	public static Date parseToDate(String d) {
		String date;
		String offset;
		if (d.indexOf('-') > 0) {
			int idx = d.indexOf('-');
			date = d.substring(0, idx).trim();
			offset = d.substring(idx).trim();
		} else if (d.indexOf('+') > 0) {
			int idx = d.indexOf('+');
			date = d.substring(0, idx).trim();
			offset = d.substring(idx).trim();
		} else {
			date = d;
			offset = null;
		}

		Calendar cal = Calendar.getInstance();
		cal.setTime(Now.get());
		if ("EOD".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 23);
			cal.set(Calendar.MINUTE, 59);
			cal.set(Calendar.SECOND, 59);
		} else if ("SOD".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
		} else if ("SOM".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.DAY_OF_MONTH, 1);
		} else if ("EOM".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
		} else if ("NOW".equalsIgnoreCase(date)) {

		} 

		if (offset != null && offset.length() > 0) {
			String sign = offset.substring(0, 1);
			String unit = offset.substring(offset.length() - 1, offset.length());
			String value = offset.substring(1, offset.length() - 1);
			int i = Integer.parseInt(value);
			if (sign.equals("-"))
				i = 0 - i;
			if (unit.equalsIgnoreCase("D"))
				addBizDays(cal, i);
			else if (unit.equalsIgnoreCase("H"))
				cal.add(Calendar.HOUR_OF_DAY, i);
			else
				throw new RuntimeException("Only D and H is supported");
		}

		return cal.getTime();
	}

	public static String parse(String d, DateFormat DF) {
		String date;
		String offset;
		if (d.indexOf('-') > 0) {
			int idx = d.indexOf('-');
			date = d.substring(0, idx).trim();
			offset = d.substring(idx).trim();
		} else if (d.indexOf('+') > 0) {
			int idx = d.indexOf('+');
			date = d.substring(0, idx).trim();
			offset = d.substring(idx).trim();
		} else {
			date = d;
			offset = null;
		}

		Calendar cal = Calendar.getInstance();
		cal.setTime(Now.get());
		if ("EOD".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 23);
			cal.set(Calendar.MINUTE, 59);
			cal.set(Calendar.SECOND, 59);
		} else if ("SOD".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
		} else if ("SOM".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.DAY_OF_MONTH, 1);
		} else if ("EOM".equalsIgnoreCase(date)) {
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
		} else if ("NOW".equalsIgnoreCase(date)) {

		} else {
			return d;
		}

		if (offset != null && offset.length() > 0) {
			String sign = offset.substring(0, 1);
			String unit = offset.substring(offset.length() - 1, offset.length());
			String value = offset.substring(1, offset.length() - 1);
			int i = Integer.parseInt(value);
			if (sign.equals("-"))
				i = 0 - i;
			if (unit.equalsIgnoreCase("D"))
				addBizDays(cal, i);
			else if (unit.equalsIgnoreCase("H"))
				cal.add(Calendar.HOUR_OF_DAY, i);
			else
				throw new RuntimeException("Only D and H is supported");
		}

		Date time = cal.getTime();
		return DF.format(time);
	}

	private static void addBizDays(Calendar c, int i) {
		int j = 0;

		if (i > 0) {
			while (j < i) {
				c.add(Calendar.DATE, 1);
				if (isNoneBizDay(c)) {
					
				} else {
					j++;
				}
					
			}
		}
		
		if (i < 0) {
			while (j > i) {
				c.add(Calendar.DATE, -1);
				if (isNoneBizDay(c)) {
					
				} else {
					j--;
				}
					
			}
		}
	}

	public static boolean isNoneBizDay(Calendar c) {
		int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
		if (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY)
			return true;

		return Holiday.isHoliday(c.getTime());		
	}
	
	public static void main(String[] args) {
		System.out.println(parse("EOD"));
		System.out.println(parse("SOD"));
		System.out.println(parse("SOM"));
		System.out.println(parse("EOM"));

		System.out.println(parse("SOD-1D"));
		System.out.println(parse("EOD-6H"));
		System.out.println(parse("EOD-2D"));
		System.out.println(parse("now-1d", new SimpleDateFormat("yyyyMMdd")));
		System.out.println(parse("now+1d", new SimpleDateFormat("yyyyMMdd")));

		System.out.println(parse("11/13/2008:23:59:59"));
	}
}
